import 'dart:io';

import 'package:ffmpeg_plugin/ffmpeg_plugin.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';

/**
 *
 * @ProjectName:    ffmpeg_plugin
 * @ClassName:      video_util
 * @Description:    dart文件描述
 * @Author:         孙浩
 * @QQ:             243280864
 * @CreateDate:     2020/10/15 13:40
 */
class VideoUtil {
  MethodChannel _channel;
  MessageHandler _handler;
  Function _success;
  Function _cancel;
  ValueChanged<String> _error;
  ValueChanged<ProgressData> _progressCallBack;

  VideoUtil() {
    _channel = FfmpegPlugin.channel;
    _channel.setMethodCallHandler((call) {
      switch (call.method) {
        case "success":
          _success?.call();
          break;
        case "cancel":
          _cancel?.call();
          break;
        case "error":
          _error?.call(call.arguments["data"]["errorMessage"].toString());
          break;
        case "progressListener":
          _progressCallBack?.call(ProgressData(
              double.parse(call.arguments["data"]["progress"].toString()),
              double.parse(call.arguments["data"]["progressTime"].toString())));
          break;
        default:
          break;
      }
      return Future.value("");
    });
  }

  void initListener({
    @required Function success,
    @required Function cancel,
    @required ValueChanged<String> error,
    @required ValueChanged<ProgressData> progressCallBack,
  }) {
    _success = success;
    _cancel = cancel;
    _error = error;
    _progressCallBack = progressCallBack;
  }

  Future cutVideoFrom2(
    String videoPath,
    String cutPath, {
    @required String startTime,
    @required String endTime,
  }) async {
    await _channel.invokeMethod("dealWithCommends", {
      "commend": [
        "-ss",
        startTime,
        "-i",
        videoPath,
        "-to",
        endTime,
        "-c",
        "copy",
        "-copyts",
        cutPath
      ]
    });
  }

  Future cutVideoFromTimeAdd(
    String videoPath,
    String cutPath, {
    @required String startTime,
    @required String timeLong,
  }) async {
    await _channel.invokeMethod("dealWithCommends", {
      "commend": [
        "-ss",
        startTime,
        "-i",
        videoPath,
        "-t",
        timeLong,
        "-c",
        "copy",
        "-copyts",
        cutPath
      ]
    });
  }

  Future cutVideo(String videoPath, String compressPath,
      {@required String startTime,
      int timeLength,
      String endTime,
      bool isAdd = true}) async {}

  Future cutVideoPreFrame(String videoPath, String picDir,
      {int purSecond = 1}) async {
    var file = Directory(picDir);
    bool isExist = await file.exists();
    if (!isExist) {
      await file.create();
    } else {
      file.listSync().forEach((element) async {
        await element.delete();
      });
    }
    await _channel.invokeMethod("dealWithCommends", {
      "commend": [
        "-i",
        videoPath,
        "-vf",
        "fps=${(1 / purSecond).toDouble()}",
        "-q:v",
        "10",
        "-preset",
        "superfast",
        "$picDir/%3d.jpg"
      ]
    });
  }

  Future compressVideoAuto(String videoPath, String compressPath) async {
    VideoInfoData data = await getInfo(videoPath);
    print(data);
    if (data.height > 3000 || data.width > 3000) {
      await compress4k(videoPath, compressPath, videoData: data);
    } else {
      await compressVideo(videoPath, compressPath, videoData: data);
    }
  }

  Future compressVideo(String videoPath, String compressPath,
      {VideoInfoData videoData}) async {
    VideoInfoData data = videoData ?? await getInfo(videoPath);
    await _channel.invokeMethod("dealWithCommends", {
      "commend": [
        "-i",
        videoPath,
        "-b",
        "2097k",
        "-vcodec",
        "libx264",
        "-preset",
//        scaleCommend,
        "superfast",
        compressPath
      ]
    });
  }

  Future compress4k(String videoPath, String compressPath,
      {VideoInfoData videoData}) async {
    VideoInfoData data = videoData ?? await getInfo(videoPath);
    String scaleCommend;
    if (data.rotation == 90 || (data.rotation == 0&& data.height > data.width) ) {
      scaleCommend = "scale=720:-1";
    } else {
      scaleCommend = "scale=-1:720";
    }
    await _channel.invokeMethod("dealWithCommends", {
      "commend": [
        "-i",
        videoPath,
        "-b",
        "3000k",
        "-vcodec",
        "libx264",
        "-vf",
        scaleCommend,
        "-preset",
        "superfast",
        compressPath
      ]
    });
  }

  Future exCommend(String commend) async {
    await _channel.invokeMethod("dealWithSingleCommend", {
      "commend": commend
    });
  }

  Future<VideoInfoData> getInfo(String videoPath) async {
    var data =
        await _channel.invokeMethod("getVideoInfo", {"videoPath": videoPath});
    var value = data["data"];
    return VideoInfoData(double.parse(value["height"]),
        double.parse(value["width"]), double.parse(value["rotation"]));
  }

  Future cancel() async {
    await _channel.invokeMethod("cancel");
  }
}

class ProgressData {
  double progress;
  double progressTime;

  ProgressData(this.progress, this.progressTime);

  @override
  String toString() {
    return 'ProgressData{progress: $progress, progressTime: $progressTime}';
  }
}

class VideoInfoData {
  double height;
  double width;
  double rotation;

  VideoInfoData(this.height, this.width, this.rotation);

  @override
  String toString() {
    return 'VideoInfoData{height: $height, width: $width, rotation: $rotation}';
  }
}
